﻿using System;
using System.Runtime.InteropServices;

namespace CredProvider.NET
{
    static class PInvoke
    {
        //http://www.pinvoke.net/default.aspx/secur32/LsaLogonUser.html
        [StructLayout(LayoutKind.Sequential)]
        public struct LSA_STRING
        {
            public UInt16 Length;
            public UInt16 MaximumLength;
            public /*PCHAR*/ IntPtr Buffer;
        }


        /// <summary>
        /// 它封装了 Windows API 中的 LSA_UNICODE_STRING 结构体。
        /// LSA_UNICODE_STRING 结构体用于表示 Unicode 字符串，
        /// 并且在许多 Windows API 函数中使用。LsaStringWrapper 类提供了一些方便的方法来创建、复制和销毁 LSA_UNICODE_STRING 结构体，
        /// 从而简化了在 C++ 代码中使用 Unicode 字符串的过程。
        /// </summary>
        public class LsaStringWrapper : IDisposable
        {
            public LSA_STRING _string;

            public LsaStringWrapper(string value)
            {
                _string = new LSA_STRING();
                _string.Length = (ushort)value.Length;
                _string.MaximumLength = (ushort)value.Length;
                _string.Buffer = Marshal.StringToHGlobalAnsi(value);
            }

            ~LsaStringWrapper()
            {
                Dispose(false);
            }

            private void Dispose(bool disposing)
            {
                if (_string.Buffer != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(_string.Buffer);
                    _string.Buffer = IntPtr.Zero;
                }
                if (disposing)
                    GC.SuppressFinalize(this);
            }

            public void Dispose()
            {
                Dispose(true);
            }
        }

        /// <summary>
        /// 它用于连接到本地安全授权服务 (LSA)。LsaConnectUntrusted 函数返回一个句柄，
        /// 该句柄可以用于调用其他 LSA API 函数。LsaConnectUntrusted 函数的参数是一个指向 LSA_UNICODE_STRING 结构体的指针，
        /// 该结构体包含要连接的 LSA 服务器的名称。如果您想要连接到本地 LSA 服务器，则可以将该参数设置为 NULL
        /// </summary>
        /// <param name="lsaHandle"></param>
        /// <returns></returns>
        [DllImport("secur32.dll", SetLastError = false)]
        public static extern uint LsaConnectUntrusted([Out] out IntPtr lsaHandle);


        /// <summary>
        /// 它用于查找指定身份验证包的标识符。身份验证包是一种 Windows 认证提供程序，它提供了用于验证用户凭据的功能。
        /// 当用户尝试登录到 Windows 计算机时，Windows 安全子系统会使用身份验证包来验证用户的用户名和密码。
        /// 如果用户名和密码是有效的，则用户将被授予访问计算机的权限。如果用户名和密码无效，则用户将被拒绝访问计算机。
        ///LsaLookupAuthenticationPackage 函数的参数是一个指向 LSA_STRING 结构体的指针，该结构体包含要查找的身份验证包的名称。
        /// 如果函数成功，则返回身份验证包的标识符。您可以使用此标识符来调用其他 LSA API 函数
        /// </summary>
        /// <param name="lsaHandle"></param>
        /// <param name="packageName"></param>
        /// <param name="authenticationPackage"></param>
        /// <returns></returns>
        [DllImport("secur32.dll", SetLastError = false)]
        public static extern uint LsaLookupAuthenticationPackage([In] IntPtr lsaHandle, [In] ref LSA_STRING packageName, [Out] out UInt32 authenticationPackage);


        /// <summary>
        /// 它用于注销当前进程的登录过程。
        /// 当您的应用程序使用 LSA API 函数连接到本地安全授权服务 (LSA) 并注册登录过程时，
        /// 您需要在应用程序退出时调用 LsaDeregisterLogonProcess 函数来注销登录过程。
        /// 这将确保您的应用程序不会在退出后继续保留登录过程的句柄，从而避免资源泄漏和安全问题。
        /// </summary>
        /// <param name="lsaHandle"></param>
        /// <returns></returns>
        [DllImport("secur32.dll", SetLastError = false)]
        public static extern uint LsaDeregisterLogonProcess([In] IntPtr lsaHandle);

        /// <summary>
        /// 它用于将凭据打包到一个缓冲区中，以便将其传递给其他进程。
        /// 当您的应用程序需要将凭据传递给其他进程时，您可以使用 CredPackAuthenticationBuffer 函数将凭据打包到一个缓冲区中，并将该缓冲区传递给其他进程。
        /// 其他进程可以使用 CredUnPackAuthenticationBuffer 函数来解包凭据并使用它们进行身份验证。
        ///CredPackAuthenticationBuffer 函数的参数包括要打包的凭据、凭据类型、目标名称和一个指向缓冲区的指针。
        /// 如果函数成功，则缓冲区将包含打包的凭据。您可以将此缓冲区传递给其他进程，以便它们可以使用 CredUnPackAuthenticationBuffer 函数来解包凭据并使用它们进行身份验证。
        /// </summary>
        /// <param name="dwFlags"></param>
        /// <param name="pszUserName"></param>
        /// <param name="pszPassword"></param>
        /// <param name="pPackedCredentials"></param>
        /// <param name="pcbPackedCredentials"></param>
        /// <returns></returns>
        [DllImport("credui.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CredPackAuthenticationBuffer(
            int dwFlags,
            string pszUserName,
            string pszPassword,
            IntPtr pPackedCredentials,
            ref int pcbPackedCredentials
        );
    }
}
